local handler = require "handler"
local util = require "util"
local reason = require "reason"
local error_code = require "error_code"
local constant = require "constant"
local cocall = require "cocall"

local table_insert = table.insert
local table_sort = table.sort
local math_floor = math.floor
local notify_money_changed = handler.notify_money_changed
local add_awards = handler.add_awards
local tostring = tostring

local friend_handler = {}

local function get_friend_coins(uid)
    local ok,curr_coins = R().basesvr({key=uid}):call('.msg_handler','get_coins',uid)
    if not ok then
        errlog(uid,'failed to pay ticket',coins,succ)
        return 0
    end

    return curr_coins
end

local function friend_cmp(a,b)
    local a_online = (a.online and 1) or 0
    local b_online = (b.online and 1) or 0
    if a_online ~= b_online then
        return a_online > b_online
    end

    if a.coins ~= b.coins then
        return a.coins > b.coins
    end

    return a.uid > b.uid
end

function friend_handler.REQ_FRIEND_LIST(msg)
    local uid = player.uid
    local ok,uid_time_map = R().friendsvr(1):call('.relation','get_friend_list',uid)
    if not ok then
        errlog(uid,'failed to get_friend_list')
        send_to_gateway('friend.RSP_FRIEND_LIST',{result = -1})
        return
    end

    local uid_list = {}
    local batch_requests = {}
    for uid in pairs(uid_time_map) do
        table_insert(uid_list,uid)
        table_insert(batch_requests,{f = get_friend_coins,id = uid,params = {uid}})
    end

    local ok,uid_info_map = R().friendsvr(1):call('.info_mgr','get_infos',uid_list)
    if not ok then
        errlog(uid,'failed to info_mgr')
        send_to_gateway('friend.RSP_FRIEND_LIST',{result = -2})
        return
    end

    --获取其金币
    local ok,results = cocall(5,batch_requests)
    if not ok then
        errlog('failed to cocall',tostring_r(results))
    end

    local friend_list = {}

    for uid in pairs(uid_time_map) do
        local info = uid_info_map[uid] or {}
        table_insert(friend_list,{
            uid = uid,
            name = info.name or '',
            icon = info.icon or '',
            coins = results[uid] or 0,
            curr_game_type = info.curr_game_type,
            online = info.online,
        })
    end
    table_sort(friend_list,friend_cmp)
    send_to_gateway('friend.RSP_FRIEND_LIST',{friend_list = friend_list})

    return true
end

function friend_handler.REQ_SEARCH_FRIEND(msg)
    local uid = player.uid
    local target_uid = msg.uid
    local ok,uid_info_map = R().friendsvr(1):call('.info_mgr','get_infos',{target_uid})
    if not ok then
        errlog(uid,'failed to get_infos',target_uid)
        send_to_gateway('friend.RSP_SEARCH_FRIEND',{result = -1})
        return
    end

    local info = uid_info_map[target_uid]
    if not info then
        dbglog(uid,'failed to get_infos',target_uid)
        send_to_gateway('friend.RSP_SEARCH_FRIEND',{exist = false})
        return
    end

    local curr_coins = get_friend_coins(target_uid)
    local rsp_info = {
        uid = target_uid,
        name = info.name,
        icon = info.icon,
        coins = curr_coins,
        curr_game_type = info.curr_game_type,
        online = info.online,
    }

    send_to_gateway('friend.RSP_SEARCH_FRIEND',{exist = true,friend_info = rsp_info})
    
    return true
end

function friend_handler.REQ_ADD_FRIEND(msg)
    local uid = player.uid
    local target_uid = msg.uid

    if uid == target_uid then
        send_to_gateway('friend.RSP_ADD_FRIEND',{result = error_code.FRIEND_CANT_ADD_SELF})
        return
    end

    --是不是有这个人先
    local ok,uid_info_map = R().friendsvr(1):call('.info_mgr','get_infos',{target_uid})
    if not ok then
        errlog(uid,'failed to get_infos',target_uid)
        send_to_gateway('friend.RSP_ADD_FRIEND',{result = -1000})
        return
    end

    local info = uid_info_map[target_uid]
    if not info then
        dbglog(uid,'failed to get_infos',target_uid)
        send_to_gateway('friend.RSP_ADD_FRIEND',
            {result = error_code.FRIEND_NO_SUCH_PLAYER})
        return
    end

    --判断下是否已经有这个好友了
    local ok,succ,ret = R().friendsvr(1):call('.relation','can_add_friend',uid,target_uid)
    if not ok then
        errlog(uid,'failed to can_add_friend',target_uid)
        send_to_gateway('friend.RSP_ADD_FRIEND',{result = -1001})
        return
    end

    if not succ then
        if ret == -1 then
            ret = error_code.FRIEND_FRIEND_EXISTED
        elseif ret == -2 then
            ret = error_code.FRIEND_REACH_LIMITATION
        end
        send_to_gateway('friend.RSP_ADD_FRIEND',{result = ret})
        return
    end

    local ok,succ,ret = R().friendsvr(1):call('.request_mgr','add_friend_request',target_uid,uid)
    if not ok then
        errlog(uid,'failed to add_friend_request',target_uid)
        send_to_gateway('friend.RSP_ADD_FRIEND',{result = -1002})
        return
    end

    if not succ then
        if ret == -1 then
            ret = error_code.FRIEND_ALREADY_REQUESTED
        end
        send_to_gateway('friend.RSP_ADD_FRIEND',{result = ret})
        return
    end

    send_to_gateway('friend.RSP_ADD_FRIEND',{uid = target_uid})

    R().hallsvr{key=target_uid}:send('.msg_handler','toagent',target_uid,'send_to_gateway',
        'hall.NTF_RED_POINTS',{module_list = {constant.MODULE_DEF.FRIEND}})

    return true
end

function friend_handler.REQ_REQUEST_PANEL(msg)
    local uid = player.uid
    local ok,ret = R().friendsvr(1):call('.request_mgr','get_all_requests',uid)
    if not ok then
        errlog(uid,'failed to can_add_friend')
        send_to_gateway('friend.RSP_REQUEST_PANEL',{result = -2001})
        return
    end

    local uid_list = {}
    local batch_requests = {}
    for _,v in pairs(ret) do
        local uid = v.uid
        table_insert(uid_list,uid)
        table_insert(batch_requests,{f = get_friend_coins,id = uid,params = {uid}})
    end

    local ok,uid_info_map = R().friendsvr(1):call('.info_mgr','get_infos',uid_list)
    if not ok then
        errlog(uid,'failed to info_mgr')
        send_to_gateway('friend.RSP_REQUEST_PANEL',{result = -2002})
        return
    end

    --获取其金币
    local ok,results = cocall(5,batch_requests)
    if not ok then
        errlog('failed to cocall',tostring_r(results))
    end

    local rsp_request_list = {}
    for _,v in pairs(ret) do
        local uid = v.uid
        local info = uid_info_map[uid] or {}
        local r = {
            uid = uid,
            name = info.name or '',
            icon = info.icon or '',
            coins = results[uid] or 0,
            status = v.status,
        }
        table_insert(rsp_request_list,1,r)
    end

    send_to_gateway('friend.RSP_REQUEST_PANEL',{request_list = rsp_request_list})

    return true
end

function friend_handler.REQ_AUDIT_REQUEST(msg)
    local uid = player.uid
    local target_uid = msg.uid
    local accepted = msg.accepted

    --先判断下是否有该玩家的请求，并且判断是否还未处理过
    local ok,succ,ret = R().friendsvr(1):call('.request_mgr','handle_friend_request',
        uid,target_uid,accepted)
    if not ok then
        errlog(uid,'failed to get_request')
        send_to_gateway('friend.RSP_AUDIT_REQUEST',{result = -3001})
        return
    end

    if not succ then
        if ret == -1 then
            ret = error_code.FRIEND_NO_SUCH_REQUEST
        elseif ret == -2 then
            ret = error_code.FRIEND_HANDLED_REQUEST
        end
        send_to_gateway('friend.RSP_AUDIT_REQUEST',{result = ret})
        return
    end

    if not accepted then
        --拒绝的话，需要给对方一条回应
        R().friendsvr(1):send('.request_mgr','add_refuse_request',target_uid,uid)
        R().friendsvr(1):send('.request_mgr','delete_request',uid,target_uid)
        send_to_gateway('friend.RSP_AUDIT_REQUEST',{uid = target_uid,accepted = accepted})
        return true
    end

    local ok,succ,ret = R().friendsvr(1):call('.relation','add_friend',uid,target_uid)
    if not ok then
        errlog(uid,'failed to add_friend',target_uid)
        R().friendsvr(1):send('.request_mgr','reset_request',uid,target_uid)
        send_to_gateway('friend.RSP_AUDIT_REQUEST',{result = -3002})
        return
    end

    if not succ then
        if ret == -1 then
            ret = error_code.FRIEND_MY_LIST_IS_FULL
        elseif ret == -2 then
            ret = error_code.FRIEND_PEER_LIST_IS_FULL
        end
        errlog(uid,'failed to add_friend',target_uid)
        R().friendsvr(1):send('.request_mgr','reset_request',uid,target_uid)
        send_to_gateway('friend.RSP_AUDIT_REQUEST',{result = ret})
        return
    end

    R().friendsvr(1):send('.request_mgr','delete_request',uid,target_uid)
    send_to_gateway('friend.RSP_AUDIT_REQUEST',{uid = target_uid,accepted = accepted})
    return true
end

function friend_handler.REQ_DELETE_FRIEND(msg)
    local uid = player.uid
    local target_uid = msg.uid
    local ok,succ,ret = R().friendsvr(1):call('.relation','delete_friend',uid,target_uid)
    if not ok or not succ then
        errlog(uid,'failed to delete_friend',target_uid,ret)
        send_to_gateway('friend.RSP_DELETE_FRIEND',{result = error_code.FRIEND_FAILED_TO_DELETE})
        return
    end

    send_to_gateway('friend.RSP_DELETE_FRIEND',{uid = target_uid})

    return true
end

--------------------------------------------------------
handler.register_module_handlers('friend',friend_handler)

